{{!

  Copyright (c) Meta Platforms, Inc. and affiliates.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

}}
{{#import "method_decorators/params" as params}}

{{!
  decorator_interface_functions - Function declarations for method
  decorator functions for a given t_service, e.g the before_* and after_*
  methods for each interface method.
}}
{{#let partial decorator_interface_functions |service| captures |params|}}
{{#if (object.eq? service.extends null)}}
{{#else}}
{{! We recursively include the declarations for functions in parent services}}
  // BEGIN inherited methods from {{service.qualified_name}}
{{#partial decorator_interface_functions service=service.extends}}
  // END inherited methods from {{service.qualified_name}}
{{/if (object.eq? service.extends null)}}
{{#each service.functions as |function|}}
  virtual void before_{{function.cpp_name}}(BeforeParams /*beforeParams*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) {}
  virtual void after_{{function.cpp_name}}(AfterParams /*afterParams*/{{#partial params.after_param_unused service=service function=function}}) {}
{{/each}}
{{/let partial}}

{{!
  decorator_interaction_functions - These are the before_ and after_ methods
  for interactions that are associated with a given t_service.
}}
{{#let partial decorator_interaction_functions |service| captures |params|}}
{{#if (object.eq? service.extends null)}}
{{#else}}{{! We need to recursively include the interactions of any parent services}}
{{#partial decorator_interaction_functions service=service.extends}}
{{/if (object.eq? service.extends null)}}
{{#each service.interactions as |interaction|}}
  // BEGIN interaction {{interaction.name}} methods
{{#each interaction.functions as |function|}}
  virtual void before_{{interaction.name}}_{{function.cpp_name}}(BeforeParams /*beforeParams*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) {}
  virtual void after_{{interaction.name}}_{{function.cpp_name}}(AfterParams /*afterParams*/{{#partial params.after_param_unused service=service function=function}}) {}
{{/each}}
  // END interaction {{interaction.name}} methods
{{/each}}
{{/let partial}}

{{!
  decorator_interface_declaration - The full method decorator declaration for a given t_service, e.g
  ServiceMethodDecorator<MyService>.
}}
{{#let partial decorator_interface_declaration |service| captures |decorator_interface_functions decorator_interaction_functions|}}
template <>
class ServiceMethodDecorator<{{service.qualified_name}}> : public ServiceMethodDecoratorBase {
 public:
  virtual ~ServiceMethodDecorator() = default;
{{#partial decorator_interface_functions service=service}}
{{#partial decorator_interaction_functions service=service}}
};
{{/let partial}}

{{!
  override_methods_no_decorators - If this interface has no
  decorators, we override any parent decorator helpers to be noops
}}
{{#let partial override_methods_no_decorators |service| captures |params|}}
{{#if (object.eq? service.extends null)}}
{{#else}}
{{#partial override_methods_no_decorators  service=service.extends}}
{{/if (object.eq? service.extends null)}}
{{#each service.functions as |function|}}
  void fbthrift_execute_decorators_before_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) override {}
  void fbthrift_execute_decorators_after_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}}) override {}
{{/each}}
{{#each service.interactions as |interaction|}}{{#each interaction.functions as |function|}}
  void fbthrift_execute_decorators_before_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) override {}
  void fbthrift_execute_decorators_after_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}}) override {}
{{/each}}{{/each}}
{{/let partial}}

{{!
  override_methods_has_decorators - if this interface has decorators and has
  a parent interface, we need to override the decorators methods so that they
  call the methods on this interface's decorators. The implementation will be
  in the cpp file in this case.
}}
{{#let partial override_methods_has_decorators |service| captures |params|}}
{{#if (object.eq? service.extends null)}}
{{#else}}
{{#partial override_methods_has_decorators service=service.extends}}
{{/if (object.eq? service.extends null)}}
{{#each service.functions as |function|}}
  void fbthrift_execute_decorators_before_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) override;
  void fbthrift_execute_decorators_after_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}}) override;
{{/each}}
{{#each service.interactions as |interaction|}}{{#each interaction.functions as |function|}}
  void fbthrift_execute_decorators_before_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) override;
  void fbthrift_execute_decorators_after_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}}) override;
{{/each}}{{/each}}
{{/let partial}}

{{!
  handler_declarations - These are additional fields / methods we declare on the
  handler.
}}
{{#let export partial handler_declarations |service| captures |override_methods_no_decorators override_methods_has_decorators params|}}
{{#if service.interaction?}}{{#else}}{{! None of this applies to interaction handlers}}
 public:
{{#if service.cpp_requires_method_decorator?}}
  std::vector<std::reference_wrapper<ServiceMethodDecoratorBase>> fbthrift_getDecorators() override;
{{#if (object.eq? service.extends null)}}{{#else}}{{#partial override_methods_has_decorators service=service.extends}}{{/if (object.eq? service.extends null)}}
{{#each service.functions as |function|}}
  virtual void fbthrift_execute_decorators_before_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}});
  virtual void fbthrift_execute_decorators_after_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}});
  static void fbthrift_invoke_decorator_after_{{function.cpp_name}}(void* iface, apache::thrift::Cpp2RequestContext* ctx{{#partial params.after_param service=service function=function}}) {
    static_cast<ServiceHandler<{{service.qualified_name}}>*>(iface)->fbthrift_execute_decorators_after_{{function.cpp_name}}(*ctx{{#partial params.after_invocation_args function=function}});
  }
{{/each}}
{{#each service.interactions as |interaction|}}{{#each interaction.functions as |function|}}
  virtual void fbthrift_execute_decorators_before_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}});
  virtual void fbthrift_execute_decorators_after_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}});
  static void fbthrift_invoke_decorator_after_{{interaction.name}}_{{function.cpp_name}}(void* iface, apache::thrift::Cpp2RequestContext* ctx{{#partial params.after_param service=service function=function}}) {
    static_cast<ServiceHandler<{{service.qualified_name}}>*>(iface)->fbthrift_execute_decorators_after_{{interaction.name}}_{{function.cpp_name}}(*ctx{{#partial params.after_invocation_args function=function}});
  }
{{/each}}{{/each}}
 private:
  ServiceMethodDecoratorList<{{service.qualified_name}}> fbthrift_methodDecorators_;
  friend void decorate(ServiceHandler<{{service.qualified_name}}>&, ServiceMethodDecoratorList<{{service.qualified_name}}>);
{{#else}}
{{#if (object.eq? service.extends null)}}{{#else}}{{#partial override_methods_no_decorators service=service.extends}}{{/if (object.eq? service.extends null)}}
{{#each service.functions as |function|}}
  virtual void fbthrift_execute_decorators_before_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) {}
  virtual void fbthrift_execute_decorators_after_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}}) {}
  static void fbthrift_invoke_decorator_after_{{function.cpp_name}}(void* iface, apache::thrift::Cpp2RequestContext* ctx{{#partial params.after_param service=service function=function}}) {
    static_cast<ServiceHandler<{{service.qualified_name}}>*>(iface)->fbthrift_execute_decorators_after_{{function.cpp_name}}(*ctx{{#partial params.after_invocation_args function=function}});
  }
{{/each}}
{{#each service.interactions as |interaction|}}{{#each interaction.functions as |function|}}
  virtual void fbthrift_execute_decorators_before_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#each function.params.fields as |param|}}, {{#partial params.param_type param=param}} /*{{#partial params.param_name param=param}}*/{{/each}}) {}
  virtual void fbthrift_execute_decorators_after_{{interaction.name}}_{{function.cpp_name}}(apache::thrift::Cpp2RequestContext& /*requestCtx*/{{#partial params.after_param_unused service=service function=function}}) {}
  static void fbthrift_invoke_decorator_after_{{interaction.name}}_{{function.cpp_name}}(void* iface, apache::thrift::Cpp2RequestContext* ctx{{#partial params.after_param service=service function=function}}) {
    static_cast<ServiceHandler<{{service.qualified_name}}>*>(iface)->fbthrift_execute_decorators_after_{{interaction.name}}_{{function.cpp_name}}(*ctx{{#partial params.after_invocation_args function=function}});
  }
{{/each}}{{/each}}
{{/if service.cpp_requires_method_decorator?}}
{{/if service.interaction?}}
{{/let partial}}

{{!
  additional_declarations - These are additional declarations that are generated
  if the service generates the decorator interface - currently just the
  decorator function
}}
{{#let export partial additional_declarations |service| captures |decorator_interface_declaration params|}}
{{#if service.interaction?}}{{#else}}{{! None of this applies to interaction handlers}}{{#if service.cpp_requires_method_decorator?}}

{{#partial decorator_interface_declaration service=service}}

void decorate(ServiceHandler<{{service.qualified_name}}>& handler, ServiceMethodDecoratorList<{{service.qualified_name}}> decorators);
{{/if service.cpp_requires_method_decorator?}}{{/if service.interaction?}}
{{/let partial}}
